package phototransfer.model.filetransfer;

import android.util.Log;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class AckReceiver extends Thread {
   public static final String TAG = "AckReceiver";
   private DatagramSocket socket = new DatagramSocket();
   private DatagramPacket packet;
   private ByteBuffer buffer = ByteBuffer.allocate(12);
   private int previousAckReceived;
   private int lastAckReceived;
   private boolean doneListening;
   private Lock lock;
   private Condition ackReceived;
   private FileSendBuffer sender;
   private static final int ACK_PACKET_SIZE = 12;

   public AckReceiver() throws SocketException {
      this.packet = new DatagramPacket(this.buffer.array(), 12);
      this.previousAckReceived = -1;
      this.lastAckReceived = -1;
      this.doneListening = false;
      this.sender = null;
      this.lock = new ReentrantLock();
      this.ackReceived = this.lock.newCondition();
   }

   public void setSendBuffer(FileSendBuffer sender) {
      this.sender = sender;
   }

   public int getPort() {
      return this.socket.getLocalPort();
   }

   public void run() {
      while(!this.doneListening) {
         try {
            this.socket.receive(this.packet);
         } catch (IOException var2) {
            continue;
         }

         if (this.buffer.capacity() < 12) {
            Log.d("AckReceiver", "[recv corrupt ack]");
         } else {
            int ackValue = this.buffer.getInt(0);
            if (ackValue == this.buffer.getInt(4) && ackValue == this.buffer.getInt(8)) {
               System.out.format("[recv ack] %d\n", ackValue);
               this.updateLastAckReceived(ackValue);
               if (this.sender != null) {
                  this.sender.setLastAck(this.lastAckReceived);
                  if (this.previousAckReceived == ackValue) {
                     this.sender.resendPacket(ackValue + 1);
                  }
               }

               this.previousAckReceived = ackValue;
            } else {
               Log.d("AckReceiver", "[recv corrupt ack]");
            }
         }
      }

      this.socket.close();
   }

   public boolean waitForAck(int expectedAck, long timeoutInMS) {
      this.lock.lock();

      try {
         while(this.lastAckReceived < expectedAck) {
            try {
               if (!this.ackReceived.await(timeoutInMS, TimeUnit.MILLISECONDS)) {
                  boolean var4 = false;
                  return var4;
               }
            } catch (InterruptedException var9) {
               boolean var5 = false;
               return var5;
            }
         }
      } finally {
         this.lock.unlock();
      }

      return true;
   }

   public void stopListening() {
      this.doneListening = true;
      this.socket.close();
   }

   private void updateLastAckReceived(int newAck) {
      this.lock.lock();

      try {
         if (newAck >= this.lastAckReceived) {
            this.lastAckReceived = newAck;
            this.ackReceived.signal();
         }
      } finally {
         this.lock.unlock();
      }

   }
}
